#include "bsp_at24c02.h"

#include "main.h"

#include "bsp_delay_us.h"

#define AT24C02_WR_ADDR (0xa0)
#define AT24C02_RD_ADDR (0xa1)

#define AT24C02_SIZE (256u)

static void at24c02_scl_wr(uint8_t value)
{
	HAL_GPIO_WritePin(AT24C02_SCL_GPIO_Port, AT24C02_SCL_Pin, (GPIO_PinState)value);
	delay_us(2);
}

static void at24c02_sda_wr(uint8_t value)
{
	HAL_GPIO_WritePin(AT24C02_SDA_GPIO_Port, AT24C02_SDA_Pin, (GPIO_PinState)value);
}

static uint8_t at24c02_sda_rd(void)
{
	return HAL_GPIO_ReadPin(AT24C02_SDA_GPIO_Port, AT24C02_SDA_Pin);
}

static sw_i2c_t at24c02_i2c = {
	.scl_wr = at24c02_scl_wr,
	.sda_wr = at24c02_sda_wr,
	.sda_rd = at24c02_sda_rd};

static uint8_t at24c02_wr_byte(uint8_t addr, uint8_t data)
{
	sw_i2c_start(&at24c02_i2c);

	sw_i2c_send_byte(&at24c02_i2c, AT24C02_WR_ADDR);
	if (sw_i2c_recv_ack(&at24c02_i2c))
	{
		return 0;
	}

	sw_i2c_send_byte(&at24c02_i2c, addr);
	if (sw_i2c_recv_ack(&at24c02_i2c))
	{
		return 0;
	}

	sw_i2c_send_byte(&at24c02_i2c, data);
	if (sw_i2c_recv_ack(&at24c02_i2c))
	{
		return 0;
	}

	sw_i2c_stop(&at24c02_i2c);

	return 1;
}

uint8_t at24c02_wr(uint8_t addr, const uint8_t *data, uint16_t len)
{
	assert_param(len >= 1 && len <= AT24C02_SIZE - addr);

	for (uint16_t i = 0; i < len; ++i)
	{
		if (!at24c02_wr_byte(addr + i, data[i]))
		{
			return 0;
		}
		HAL_Delay(5);
	}

	return 1;
}

uint8_t at24c02_rd(uint8_t addr, uint8_t *data, uint16_t len)
{
	assert_param(len >= 1 && len <= AT24C02_SIZE - addr);

	sw_i2c_start(&at24c02_i2c);

	sw_i2c_send_byte(&at24c02_i2c, AT24C02_WR_ADDR);
	if (sw_i2c_recv_ack(&at24c02_i2c))
	{
		return 0;
	}

	sw_i2c_send_byte(&at24c02_i2c, addr);
	if (sw_i2c_recv_ack(&at24c02_i2c))
	{
		return 0;
	}

	sw_i2c_start(&at24c02_i2c);

	sw_i2c_send_byte(&at24c02_i2c, AT24C02_RD_ADDR);
	if (sw_i2c_recv_ack(&at24c02_i2c))
	{
		return 0;
	}

	for (uint16_t i = 0; i < len; ++i)
	{
		data[i] = sw_i2c_recv_byte(&at24c02_i2c);
		if (i < len - 1)
		{
			sw_i2c_send_ack(&at24c02_i2c, 0);
		}
		else
		{
			sw_i2c_send_ack(&at24c02_i2c, 1);
		}
	}

	sw_i2c_stop(&at24c02_i2c);

	return 1;
}
